package cn.zhxu.toys.msg;


import cn.zhxu.toys.util.StringUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * 动态消息发送器（用于多租户模式）
 * @author Troy.Zhou
 * @since 0.0.3
 */
public class DynamicMsgSender implements MsgSender {

    /** 消息发送器池，一个平台一个 */
    private final Map<Object, AbstractMsgSender> senderPool = new HashMap<>();

    private final Object lock = new Object();

    /** 消息模板，KEY 为租户标识 */
    private Map<String, String[]> templates;

    /** 路由配置器 */
    private RoutingConfigurer routingConfigurer;

    /** 消息发送器工厂 */
    private SenderFactory senderFactory;


    public interface RoutingConfigurer {

        /**
         * 感知当前平台的主键标识
         * @return 当前租户的主键标识
         */
        Object determineCurrentLookupKey();

        /**
         * 感知当前平台的消息发送器的初始化参数
         * @param lookupKey 当前租户的主键标识
         * @return 初始化参数
         */
        Map<String, String> getInitParams(Object lookupKey);

        /**
         * 感知当前平台的模板 ID
         * @param lookupKey 当前租户的主键标识
         * @param tmplName 模板名称
         * @return 模板值
         */
        String getTmplValue(Object lookupKey, String tmplName);

    }

    /**
     * 消息发送器工厂
     */
    public interface SenderFactory {

        /**
         * 创建一个消息发送器
         * @return 消息发送器
         */
        AbstractMsgSender create();

    }

    @Override
    public boolean send(String phone, String tmplName, String... tmplArgs) {
        Object key = routingConfigurer.determineCurrentLookupKey();
        AbstractMsgSender sender;
        MsgTemplate template;
        synchronized (lock) {
            sender = senderPool.get(key);
            if (sender == null) {
                sender = senderFactory.create();
                if (sender == null) {
                    throw new IllegalStateException("the return of MsgSenderFactory#create() can not be null !");
                }
                sender.init(routingConfigurer.getInitParams(key));
                senderPool.put(key, sender);
            }
            template = sender.getMsgTemplate(tmplName);
            if (template == null) {
                String tmplValue = routingConfigurer.getTmplValue(key, tmplName);
                if (StringUtils.isBlank(tmplValue)) {
                    throw new IllegalStateException("the return of PlatformSensor#senseMsgTmplValue(" + tmplName + ") is NULL!");
                }
                String[] argsNames = templates.get(tmplName);
                if (argsNames == null) {
                    throw new IllegalStateException("No such template named: " + tmplName);
                }
                template = new MsgTemplate(tmplName, tmplValue, argsNames);
                sender.addMsgTemplate(template);
            }
        }
        return sender.send(phone, template, tmplArgs);
    }

    public void clearPool() {
        synchronized (lock) {
            senderPool.clear();
        }
    }

    public Map<String, String[]> getTemplates() {
        return templates;
    }

    public void setTemplates(Map<String, String[]> templates) {
        this.templates = templates;
    }

    public RoutingConfigurer getRoutingConfigurer() {
        return routingConfigurer;
    }

    public void setRoutingConfigurer(RoutingConfigurer routingConfigurer) {
        this.routingConfigurer = routingConfigurer;
    }

    public SenderFactory getSenderFactory() {
        return senderFactory;
    }

    public void setSenderFactory(SenderFactory senderFactory) {
        this.senderFactory = senderFactory;
    }

}
